#ifndef __MVT_LOG_H__
#define __MVT_LOG_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include "mvdef.h"
#include "mvos/mvos_apis.h"

typedef enum _syslog_mode
{
    MVT_LOG_SYSLOG_DISABLE = 0, ///< 仅modlog模式
    MVT_LOG_SYSLOG_ONLY    = 1, ///< 仅syslog模式
    MVT_LOG_SYSLOG_MIX     = 2, ///< 混合模式（暂不支持）
}mvt_log_syslog_mode_e;

typedef mv_s32_t(*pf_syslog_ff)(mv_void_t);
typedef mv_s32_t(*pf_syslog_ss)(mv_s32_t s32_size);

typedef struct _maintainer_init_args
{
    /**
     * 缓存大小(字节；至少4KB，低于则视为内存不足不启用相关功能)
     * 默认2块缓存空间，需根据系统内存评估缓存大小，一般推荐100KB一块，特别是考虑到上传调用频次，内存允许情况下，不建议太小（也不需要特别大）
     * (当同时开启log存储，log上传时，会在上传额外临时申请1块独立空间，避免影响存储效率，所以注意内存用量设置)
     */
    mv_s32_t     s32_cache_max;
    /**
     * 系统日志模式（注意当系统日志模式；当前仅AOS系统有效）
     * - AOS系统配置开启syslog后，可使能此模式；内部改为系统日志模式代替模块缓存
     */
    mv_u8_t      u8_syslog_mode;
    /**
     * 系统日志强制缓存刷写回调
     *（内部统一收到强制刷写命令时，会调用此回调通知外部syslog也要进行刷写操作，刷写后可调用done触发内部打包）
     */
    pf_syslog_ff f_on_syslog_force_flush;
    /**
     * 系统日志大小设置（>=0，0表示系统默认）
     *（内部需要调整日志输出大小时，会调用此回调通知外部syslog也要进行调整操作，外部syslog超过此大小则需要调用done触发内部打包）
     */
    pf_syslog_ss f_on_syslog_size_set;
    /**
     * cfg本地检测目录（优先使用，一般是可读写分区路径）
     */
    mv_v8ptr_t   pv8_log_cfg_root_local;
    /**
     * cfg外部检测目录（动态生效，一般是SDcard路径）
     */
    mv_v8ptr_t   pv8_log_cfg_root_extern;
    /**
     * IOTC证书路径，影响上传是否可用
     */
    mv_v8ptr_t   pv8_iotc_cert;
}mvt_log_mia_t;
#define LOG_SAVE_CFG  "logsave.j"
/**
 * @brief LOG-管理者初始化
 * 
 * @param pst_init [in] 初始化参数[mvt_log_mia_t]
 * @return 初始化结果 
 * - success : MV_EC_SUCCESS
 * -  failed : else
 *
 * @note 全局唯一，一般用于独立进程；包含log句柄注册管理、log存储、log上传等功能
 */
mv_s32_t  mvt_log_maintainer_init(mvt_log_mia_t *pst_init);
/**
 * @brief LOG-管理者查询当前syslog mode
 * 
 * @return 查询结果
 * - success : [mvt_log_syslog_mode_e]
 * -  failed : <0 
 */
mv_s32_t  mvt_log_maintainer_cur_syslog_mode(mv_void_t);
typedef struct _syslog_info
{
    union {
        mv_v8ptr_t pv8_file; ///< syslog文件
        mv_v8ptr_t pv8_data; ///< syslog内容
    };
    mv_u8_t  u8_syslog_type; ///< syslog类型（0=文件；1=内容）
    mv_s32_t s32_off;        ///< syslog偏移（跳过的重复内容）
    mv_s32_t s32_size;       ///< syslog有效数据大小
}mvt_log_sli_t;
/**
 * @brief LOG-管理者系统日志打包通知
 * 
 * @param pst_sli  [in] 系统日志信息[mvt_log_sli_t]
 * @return \
 */
mv_s32_t  mvt_log_maintainer_syslog_done(mvt_log_sli_t *pst_sli);
/************************************************/
#define LOG_MAX_NAME_SIZE   8 ///< 不包含'\0'
#define LOG_MAX_PRINT_NUM  48 ///< 最大48个句柄

typedef enum {
    LOG_LEVEL_NONE     = 0,    ///< 无打印
    LOG_LEVEL_ERROR    = 1,    ///< log等级 :　错误
    LOG_LEVEL_WARN     = 2,    ///< log等级 :　警告
    LOG_LEVEL_INFO     = 3,    ///< log等级 :　流程信息
    LOG_LEVEL_DEBUG    = 4,    ///< log等级 :　调试
    LOG_LEVEL_INVALID  = 0xff, ///< 无效值
}mvt_log_level_e;

typedef enum {
    LOG_REGION_1 = 0,
    LOG_REGION_2 = 1,
    LOG_REGION_3 = 2,
    LOG_REGION_4 = 3,
    LOG_REGION_5 = 4,
    LOG_REGION_6 = 5,
    LOG_REGION_7 = 6,
    LOG_REGION_MAX,
}mvt_log_region_e;   ///< 最多支持7个区域控制
#define REG_VAL(regnum) (1<<regnum)

typedef struct _ghdl_takeout_node
{
    mv_v8_t  av8_name[LOG_MAX_NAME_SIZE+1];
    mv_u8_t  au8_rlevel[LOG_REGION_MAX];
}mvt_log_ghdl_node_t; ///< 总计16字节
/**
 * @brief LOG-使用：License信息同步
 * 
 * @param pkey       [in] PKEY
 * @param s32_klen   [in] PKEY长度
 * @param u32_did    [in] 设备DID
 * @param pu8_check  [in] 校验信息
 * @param s32_chklen [in] 校验信息长度
 * @return 操作结果
 * - success : MV_EC_SUCCESS
 * -  failed : else
 *
 * @note 此接口有调用权限，仅供mvs服务内部调用，涉及log存储和log上传是否可用权限验证
 */
mv_s32_t  mvt_log_license_sync(mv_vptr_t pkey, mv_s32_t s32_klen, mv_u32_t u32_did, mv_u8ptr_t pu8_check, mv_s32_t s32_chklen);
/**
 * @brief LOG-使用：上传参数设置
 * 
 * @param pkey           [in] PKEY
 * @param s32_klen       [in] PKEY长度
 * @param pv8_upload_url [in] 上传URL
 * @param u32_flush_intv [in] 上报间隔（秒，定时上报）
 * @param s32_max_perlog [in] 单次上传最大大小（字节）
 * @return 设置结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 *
 * @note 此接口有调用权限，仅供mvs服务内部调用
 */
mv_s32_t  mvt_log_upload_param_set(mv_vptr_t pkey, mv_s32_t s32_klen, mv_v8ptr_t pv8_upload_url, mv_u32_t u32_flush_intv, mv_s32_t s32_max_perlog);
/**
 * @brief LOG-使用：主动flush缓存（save和upload）
 * 
 * @param u32_timeout    [in] 等待超时（秒；0=不等待）
 * @return 操作结果 
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_TIMEOUT   （调用到达，但flush等待完成超时）
 *           : MV_EC_NOT_READY （调用频次限制，本次操作忽略）
 *
 * @note 内置调用频次限制，避免恶意频繁调用
 */
mv_s32_t mvt_log_cache_flush(mv_u32_t u32_timeout);
/**
 * @brief LOG-使用：log全局句柄状态获取
 * 
 * @param cpv8_name    [in]  log模块名(可选指定句柄，或NULL，全部句柄)
 * @param ppst_takeout [out] 获取结果结构体数组（NULL入参为仅返回数量）
 * @return 操作结果
 * - >=0 : log全局句柄数量
 * - else: 错误码
 */
mv_s32_t  mvt_log_ghdl_dump(mv_cv8ptr_t cpv8_name, mvt_log_ghdl_node_t **ppst_takeout);
/**
 * @brief LOG-使用：log全局句柄初始化注册
 * 
 * @param cpv8_name  [in] log模块名
 * @param u8_glevel  [in] 模块统一初始等级[mvt_log_level_e]（注册时有效）
 * @param au8_rlevel [in] 模块区域初始等级（注册时有效）
 * @return 初始化结果
 * - success : log全局句柄
 * -  failed : NULL
 *
 * @note log模块名需要调用者自行确保唯一性，同名则认为是同一个模块；
 *       当rlevel存在时，忽略glevel（主要设计兼容旧接口）
 *       当rlevel为NULL，则以glevel设置所有区域等级
 */
mv_vptr_t mvt_log_ghdl_init(mv_cv8ptr_t cpv8_name, mv_u8_t u8_glevel, mv_u8_t au8_rlevel[LOG_REGION_MAX]);
#define mvt_log_init(name, level) mvt_log_ghdl_init(name, level, NULL) ///< 兼容旧接口
/**
 * @brief LOG-使用：全局句柄全区域等级预设（影响未初始化的句柄）
 * 
 * @param u8_act     [in] 动作（0=获取；1=设置）
 * @param au8_rlevel [in] 各区域初始等级
 * @return 控制结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 *
 * @note 当rlevel存在时，忽略glevel（主要设计兼容旧接口）
 *       当rlevel为NULL，则以glevel设置所有区域等级
 */
mv_s32_t mvt_log_ghdl_level_preset(mv_u8_t u8_act, mv_u8_t au8_rlevel[LOG_REGION_MAX]);
/**
 * @brief LOG-使用：log全局句柄查询初始化
 * 
 * @param cpv8_name  [in] log模块名
 * @return 初始化结果
 * - success : log全局句柄
 * -  failed : NULL
 *
 * @note 弱化版的mvt_log_ghdl_init，仅获取，不存在则返回NULL不会注册
 */
mv_vptr_t mvt_log_ghdl_pick(mv_cv8ptr_t cpv8_name);
/**
 * @brief LOG-使用：全局句柄全区域打印等级控制
 * 
 * @param p_handle   [in] log全局句柄
 * @param u8_glevel  [in] 统一打印等级[mvt_log_level_e]
 * @param au8_rlevel [in] 各区域初始等级
 * @return 控制结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 *
 * @note 当rlevel存在时，忽略glevel（主要设计兼容旧接口）
 *       当rlevel为NULL，则以glevel设置所有区域等级
 */
mv_s32_t  mvt_log_ghdl_level_ctrl(mv_vptr_t p_handle, mv_u8_t u8_glevel, mv_u8_t au8_rlevel[LOG_REGION_MAX]);
/**
 * @brief LOG-使用：全局句柄全区域打印等级控制(名字索引)
 * 
 * @param cpv8_name  [in] log模块名
 * @param u8_glevel  [in] 统一打印等级[mvt_log_level_e]
 * @param au8_rlevel [in] 各区域初始等级
 * @return 控制结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 *
 * @note 当rlevel存在时，忽略glevel（主要设计兼容旧接口）
 *       当rlevel为NULL，则以glevel设置所有区域等级
 */
mv_s32_t  mvt_log_ghdl_level_ctrl_byname(mv_cv8ptr_t cpv8_name, mv_u8_t u8_glevel, mv_u8_t au8_rlevel[LOG_REGION_MAX]);
#define mvt_log_ctrl(name, level) mvt_log_ghdl_level_ctrl_byname(name, level, NULL) ///< 兼容旧接口
/**
 * @brief LOG-使用：全局句柄指定打印区域等级控制
 * 
 * @param p_handle  [in] log句柄（全局/局部均可）
 * @param u8_regmap [in] 打印区域[mvt_log_region_e]的bitmap（可以一次指定多个区域设置同样level）
 * @param u8_level  [in] 打印等级[mvt_log_level_e]
 * @return 控制结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 */
mv_s32_t  mvt_log_ghdl_region_ctrl(mv_vptr_t p_handle, mv_u8_t u8_regmap, mv_u8_t u8_level);
/**
 * @brief log输出
 *
 * @param p_handle    [in] log句柄
 * @param u8_level    [in] 打印等级（等级高于句柄当前设置，则不会输出）
 * @param u8_region   [in] 打印区域[mvt_log_region_e]
 * @param pcv8_format [in] 输出格式
 * @param ...         [in] 格式化可变参
 * @return \
 * 
 * @note 64bit变参，强烈建议使用MVOS_VA64()封套入参
 */
mv_void_t mvt_log_rprintf(mv_vptr_t p_handle, mv_u8_t u8_level, mv_u8_t u8_region, mv_cv8ptr_t pcv8_format, ...);
/** 兼容旧接口，默认0区域为主输出区域 */
#define mvt_log_printf(phdl, level, fmt, ...) mvt_log_rprintf(phdl, level, 0, fmt, ##__VA_ARGS__)

#ifdef __cplusplus
}
#endif
#endif